#include <stdio.h>
#include <malloc.h>
#include <assert.h>
#include <string.h>
#include <time.h>
#include <stdlib.h>

#include "Monster.h"

void monsterInitUnMonstre(Monster * pMonster){

    pMonster->name = (char *)malloc(20*sizeof(char));
    pMonster->id = 0;
    pMonster->level = 0;
    pMonster->maxhp= 0;
    pMonster->curhp = 0;
    pMonster->power = 0;
    pMonster->xp = 0;
    pMonster->radius = 0;
    pMonster->x = 0;
    pMonster->y = 0;
    pMonster->x_std = 0;
    pMonster->y_std = 0;
    pMonster->direction = 0;
    pMonster->mode = 0;
    pMonster->cooldown = 0;
    pMonster->last_damage = 0;
    pMonster->speed_move = 0;
    pMonster->cooldown_move = 0;
    pMonster->cooldown_respawn = 0;
    pMonster->respawn = 0;
    pMonster->terrainid = 0;

}


Monster * monsterTabInit(int * nb,int terrainid){ /*renvoie un tableau de monstre initialisés*/

		FILE * fMonster;
		Monster * pMonsters;
		Monster * tabmonst;
		int i,j=0,res;

		fMonster = fopen("data/Database/Monsters.dat","r");
		if(fMonster == NULL)
		fMonster = fopen("../data/Database/Monsters.dat","r");
		assert(fMonster!=NULL);

		fscanf(fMonster,"#nb =%d\n",nb);


		pMonsters = (Monster *) malloc((*nb)*sizeof(Monster));
		tabmonst = (Monster *) malloc((*nb)*sizeof(Monster));

		fscanf(fMonster,"ID Name Level HP Power XP Radius X Y SPEED MOVESPEED RESPAWN TERRAINID\n");



            for(i=0;i<(*nb);i++){

            monsterInitUnMonstre(&tabmonst[i]);

           res = fscanf(fMonster,"%d %s %d %d %d %u %d %d %d %d %d %d %d\n",&((tabmonst[i]).id),(tabmonst[i]).name,
                &((tabmonst[i]).level),&((tabmonst[i]).maxhp),&((tabmonst[i]).power),
                &((tabmonst[i]).xp),&((tabmonst[i]).radius),&((tabmonst[i]).x),&((tabmonst[i]).y),&((tabmonst[i]).speed),&((tabmonst[i]).speed_move),&((tabmonst[i]).respawn),&((tabmonst[i]).terrainid));

		assert(res == 13);

			if(tabmonst[i].terrainid == terrainid) {


                (tabmonst[i]).curhp = (tabmonst[i]).maxhp;
                (tabmonst[i]).x_std = (tabmonst[i]).x;
                (tabmonst[i]).y_std = (tabmonst[i]).y;
                (tabmonst[i]).mode = 0;
                (tabmonst[i]).direction = rand()%4;
                (tabmonst[i]).cooldown = 0;
                (tabmonst[i]).cooldown_move = (float) 1 / (tabmonst[i]).speed_move;
                (tabmonst[i]).last_damage = -1;
                (tabmonst[i]).cooldown_respawn = (tabmonst[i]).respawn;
                 pMonsters[j]=tabmonst[i];

                j++;


            }else{
	free(tabmonst[i].name);
	}
        }
        *nb=j;

		fclose(fMonster);
    free(tabmonst);
	return pMonsters;
}


void monsterFree(Monster * pMonsters,int nb){ /*libere tous les monstre*/

	int i;

	for(i = 0;i<nb;i++){
		free((pMonsters+i)->name);
		(pMonsters+i)->name = NULL;
	}

	free(pMonsters);

	pMonsters = NULL;

}


void monsterGetPos(const Monster * pMonster, int * x, int * y){

		*x = pMonster->x;
		*y = pMonster->y;

}

int monsterGetDistanceX(Monster * pMonster,int x){ /*recupere la distance en x du monstre*/

    return (pMonster->x - x);

}
int monsterGetDistanceY(Monster * pMonster,int y){ /*recupere la distance en y du monstre*/

    return (pMonster->y - y);

}

int positionRadius(Monster * pMonster,int x,int y){ /*les monstres ont un rayon pour leur deplacement aléatoire, cette fonction renvoie vrai si la position est dans le rayon du monstre*/
                                                    /*et renvoie faux sinon*/
	if((x <= pMonster->x_std+pMonster->radius && x >= pMonster->x_std-pMonster->radius)
	&& (y <= pMonster->y_std+pMonster->radius && y >= pMonster->y_std-pMonster->radius))
		return 1;
	else
		return 0;



}

void monsterMove(Monster * pMonster,Terrain * pTerr){ /*fonction pour faire bouger les monstres*/


	int testx,testy;
	int dirx[] = {-1, 1, 0, 0};
    	int diry[] = {0, 0, -1, 1};
	/*if(pMonster->mode == M_COMBAT) return; si monstre en combat, il ne bouge plus: temporaire en attendant un pathfinding pour aller sur le hero*/
	if(pMonster->radius==0) {terModif(pTerr,pMonster->x,pMonster->y,1); return; } /*si radius = 0, le mob ne doit pas bouger*/
	if(pMonster->cooldown_move <= 0){
        testx = pMonster->x + dirx[pMonster->direction];
        testy = pMonster->y + diry[pMonster->direction];

        if (terTestPosition(pTerr,testx,testy) && positionRadius(pMonster,testx,testy)){
	    terModif(pTerr,pMonster->x,pMonster->y,0);
            pMonster->x = testx;
            pMonster->y = testy;
	    terModif(pTerr,pMonster->x,pMonster->y,1);

        }else{
            pMonster->direction = rand()%4;

        }
        if(pMonster->mode==M_COMBAT){ pMonster->cooldown_move = (float)1 / pMonster->speed_move; }
        else {pMonster->cooldown_move = (float)5 / pMonster->speed_move; }
	}else{
	return;
	}
}
void monsterNeedRespawn(Monster * pMonster,float interval){

	if(pMonster->mode == M_DEAD){
	pMonster->cooldown_respawn -= interval;
	}


	if(pMonster->cooldown_respawn <=0 && pMonster->mode == M_DEAD){
		pMonster->x = pMonster->x_std;
		pMonster->y = pMonster->y_std;
		pMonster->curhp = pMonster->maxhp;
		pMonster->mode = M_ALIVE;
		pMonster->cooldown_respawn = pMonster->respawn;
		pMonster->last_damage = -1;
	}

}

void monsterTakeDamage(Monster * pMonster, int dmg){ /*fonction qui gere les hp d'un monstre*/
	if(pMonster->curhp-dmg<0){
		pMonster->curhp = 0;
	}else{
		pMonster->curhp-=dmg;
	}
	monstetSetLastDamage(pMonster,dmg);
    if(pMonster->curhp<=0){
        pMonster->mode=1;

	}
}


int monsterAttack(Monster * pMonster){


return pMonster->power*0.5;

}

int monsterGetMode(const Monster * pMonster){
	return pMonster->mode;
}

int monsterGetLastDamage(const Monster * pMonster){
	return pMonster->last_damage;
}

void monstetSetLastDamage(Monster * pMonster,int dmg){
pMonster->last_damage = dmg;
}
void monsterSetMode(Monster * pMonster,int mod){
	pMonster->mode=mod;
}
void monsterSetDirection(Monster *pMonster,int d){
	pMonster->direction = d;
}
void monsterSetCooldownMove(Monster * pMonster,float interval){
	pMonster->cooldown_move -= interval;
}

float monsterGetCooldownAttack(const Monster * pMonster){
return pMonster->cooldown;
}
float monsterGetCooldownMove(const Monster * pMonster){
return pMonster->cooldown_move;
}
void monsterSetCooldownAttack(Monster * pMonster,float interval){
pMonster->cooldown -= interval;
}
int monsterGetSpeed(const Monster * pMonster){
return pMonster->speed;
}
void monsterSetCooldownMoveAbs(Monster * pMonster,float value){
pMonster->cooldown_move = value;
}
void monsterSetCooldownAttackAbs(Monster * pMonster,float value){
pMonster->cooldown = value;
}

int monsterGetExp(const Monster * pMonster){

return pMonster->xp;
}

int monsterGetId(const Monster * pMonster){
return pMonster->id;
}
char * monsterGetName(const Monster * pMonster){
return pMonster->name;
}

int monsterGetCurHP(const Monster * pMonster){
return pMonster->curhp;
}
int monsterGetMaxHP(const Monster * pMonster){
return pMonster->maxhp;
}

void monsterTestRegression(){
	Monster * tabMonsters;
	int nb_monsters;
	printf("****** TEST MONSTER START ************ \n");
	tabMonsters = monsterTabInit(&nb_monsters,1);
	monsterTakeDamage(tabMonsters+1, 3);
	if(monsterGetLastDamage(tabMonsters+1) == monsterGetMaxHP(tabMonsters+1) - monsterGetCurHP(tabMonsters+1) && nb_monsters != 0){
	printf("Module travaille correctement...\n");
	}else{
	printf("Attention! Erreur du module...\n");
	}

	monsterFree(tabMonsters,nb_monsters);
	printf("****** TEST MONSTER END ************** \n");

}

